﻿using System;
using Unis.Framework.Core.Exceptions;
using Unis.Framework.ORM;
using Unis.Framework.ORM.BaseDefiniens.Enums;
using Unis.Framework.ORM.DbSql;
using Unis.Framework.ORM.Exceptions;
using Unis.Framework.ORM.Persistence;
using Unis.ORM.Mapping;
using Unis.ORM.Persistence;

namespace Unis.ORM.DbSql
{
    public abstract class BaseSqlGenerator
    {
        // Fields
        private static BaseAutoSqlGenerator _AutoSqlConfigObject;
        private DatabaseType _DatabaseType = DatabaseConfigurationScope.CreateDatabaseType();
        private string _ParameterPrefix = SqlShareHelper.SQL_XML_CFG_PARAM_PREFIX;
        private static BaseXmlSqlConfig _XmlSqlConfigObject;

        // Methods
        public string GenerateCacheKey(Type entityType, OperationType operationType)
        {
            return (entityType.FullName + "_" + operationType.ToString());
        }

        public virtual SqlString[] GenerateDeleteSql(Type entityType)
        {
            throw new SubClassMustOverrideException("GenerateDeleteSql");
        }

        public virtual SqlString[] GenerateFindByKeySql(Type entityType, string[] properties)
        {
            throw new SubClassMustOverrideException("SubClassMustOverrideException");
        }

        public virtual SqlString[] GenerateInsertSql(Type entityType, string[] properties)
        {
            throw new SubClassMustOverrideException("GenerateInsertSql");
        }

        public virtual SqlString[] GenerateSimpleSelectSql(Type entityType, string[] properties)
        {
            throw new SubClassMustOverrideException("GenerateSelectSql");
        }

        public virtual SqlString[] GenerateSql(Type entityType, OperationType operationType, string[] properties)
        {
            string key = entityType.FullName + "_" + operationType.ToString();
            if (CacheProxy.ContainsSql(key))
            {
                return CacheProxy.GetCachedSql(key);
            }
            switch (operationType)
            {
                case OperationType.Update:
                    return this.GenerateUpdateSql(entityType, properties);

                case OperationType.Delete:
                    return this.GenerateDeleteSql(entityType);

                case OperationType.Select:
                    return this.GenerateSimpleSelectSql(entityType, properties);

                case OperationType.Insert:
                    return this.GenerateInsertSql(entityType, properties);
            }
            throw new APPException("在自动根据配置信息获取对象的操作SQL 语句时,操作类型:" + operationType.ToString() + " 还没有进行定义！");
        }

        public virtual SqlString[] GenerateUpdateSql(Type entityType, string[] properties)
        {
            throw new SubClassMustOverrideException("GenerateUpdateSql");
        }

        public int GetAutoIncreaseID(ModelMappingInfo mappingInfo)
        {
            throw new APPException("需要配置数据库自增列的处理方式！");
        }

        public static BaseSqlGenerator GetSqlGeneratorObject(ModelConfigOptions cfgOptions, string[] properties)
        {
            BaseSqlGenerator generator = null;
            if ((cfgOptions & ModelConfigOptions.CreateSqlByXmlCfg) != ModelConfigOptions.None)
            {
                if (_XmlSqlConfigObject == null)
                {
                    _XmlSqlConfigObject = new BaseXmlSqlConfig();
                }
                generator = _XmlSqlConfigObject;
            }
            else
            {
                if (_AutoSqlConfigObject == null)
                {
                    _AutoSqlConfigObject = new BaseAutoSqlGenerator();
                }
                generator = _AutoSqlConfigObject;
            }
            if ((properties == null) || (properties.Length <= 0))
            {
                return generator;
            }
            if (_AutoSqlConfigObject == null)
            {
                _AutoSqlConfigObject = new BaseAutoSqlGenerator();
            }
            return _AutoSqlConfigObject;
        }

        public void SetDatabaseType(DatabaseType databaseType)
        {
            this._DatabaseType = databaseType;
            this._ParameterPrefix = SqlShareHelper.SQL_XML_CFG_PARAM_PREFIX;
        }

        public string ToSqlVal(string val)
        {
            string str = val;
            if (string.IsNullOrEmpty(str))
            {
                if (this._DatabaseType == DatabaseType.Oracle)
                {
                    return "''";
                }
                return "NULL";
            }
            str = str.Replace("'", "''");
            return ("'" + str + "'");
        }

        // Properties
        protected string ParameterPrefix
        {
            get
            {
                return this._ParameterPrefix;
            }
        }
    }
}
